package com.lew.jlight.redis;

import com.google.common.io.Resources;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;

import redis.clients.jedis.JedisPool;
import redis.clients.jedis.exceptions.JedisDataException;

import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;

/**
 * 装载并执行
 */
public class JedisScriptExecutor {

    private static Logger logger = LoggerFactory.getLogger(JedisScriptExecutor.class);

    private final JedisTemplate jedisTemplate;

    private String script;
    private String sha1;

    public JedisScriptExecutor(JedisPool jedisPool) {
        this.jedisTemplate = new JedisTemplate(jedisPool);
    }

    public JedisScriptExecutor(JedisTemplate jedisTemplate) {
        this.jedisTemplate = jedisTemplate;
    }

    /**
     * 装载Lua Script。
     * 如果Script出错，抛出JedisDataException。
     */
    public void load(final String scriptContent) throws JedisDataException {
        checkNotNull(scriptContent, "parameter scriptContent must not be null");
        checkState(script == null, "script should be loaded only once!");
        this.sha1 = jedisTemplate.execute((JedisTemplate.JedisAction<String>) jedis -> jedis.scriptLoad(scriptContent));
        this.script = scriptContent;
        logger.debug("Script \"{}\" had been loaded as {}", scriptContent, sha1);
    }

    /**
     * 从文件加载Lua Script, 文件路径格式为Spring Resource的格式.
     */
    public void loadFromFile(final String scriptPath) throws JedisDataException {
        checkNotNull(scriptPath, "parameter scriptContent must not be null");
        URL url = Resources.getResource(scriptPath);
        String scriptContent;
        try {
            scriptContent = Resources.toString(url, StandardCharsets.UTF_8);
        } catch (IOException e) {
            throw new IllegalArgumentException(scriptPath + " is not exist.", e);
        }
        load(scriptContent);
    }

    /**
     * 执行Lua Script。
     *
     * keys与args不允许为null.
     */
    public Object execute(final String[] keys, final String[] args) throws IllegalArgumentException {
        checkNotNull(keys, "keys can't be null.");
        checkNotNull(args, "args can't be null.");
        return execute(Arrays.asList(keys), Arrays.asList(args));
    }

    /**
     * 执行Lua Script。
     *
     * keys与args不允许为null.
     */
    public Object execute(final List<String> keys, final List<String> args) throws IllegalArgumentException {
        checkNotNull(keys, "keys can't be null.");
        checkNotNull(args, "args can't be null.");
        checkState(sha1 != null, "please call load method first before execute");
        return jedisTemplate.execute((JedisTemplate.JedisAction<Object>) jedis -> jedis.evalsha(sha1, keys, args));
    }
}
